﻿using Caliburn.Micro;
using SD.Infrastructure.WPF.Caliburn.Aspects;
using SD.Infrastructure.WPF.Caliburn.Base;
using SD.Infrastructure.WPF.Models;
using SD.IOC.Core.Mediators;
using SlamDunk.MES.Client.ViewModels.Facility;
using SlamDunk.MES.Client.ViewModels.ProductionPlan;
using SlamDunk.MES.IAppService.DTOs.Outputs.DefinitionContext;
using SlamDunk.MES.IAppService.DTOs.Outputs.PlanContext;
using SlamDunk.MES.IAppService.DTOs.Outputs.ResourceContext;
using SlamDunk.MES.IAppService.Interfaces;
using SlamDunk.ValueObjects.Enums;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.ServiceModel.Extensions;
using System.Threading.Tasks;
using System.Windows;

namespace SlamDunk.MES.Client.ViewModels.ExecutionPlan
{
    /// <summary>
    /// 作业计划创建视图模型
    /// </summary>
    public class AddViewModel : ScreenBase
    {
        #region # 字段及构造器

        /// <summary>
        /// 编号生成服务契约接口代理
        /// </summary>
        private readonly ServiceProxy<INumberContract> _numberContract;

        /// <summary>
        /// 产品定义服务契约接口代理
        /// </summary>
        private readonly ServiceProxy<IDefinitionContract> _definitionContract;

        /// <summary>
        /// 计划管理服务契约接口代理
        /// </summary>
        private readonly ServiceProxy<IPlanContract> _planContract;

        /// <summary>
        /// 窗口管理器
        /// </summary>
        private readonly IWindowManager _windowManager;

        /// <summary>
        /// 依赖注入构造器
        /// </summary>
        public AddViewModel(ServiceProxy<INumberContract> numberContract, ServiceProxy<IDefinitionContract> definitionContract, ServiceProxy<IPlanContract> planContract, IWindowManager windowManager)
        {
            this._numberContract = numberContract;
            this._definitionContract = definitionContract;
            this._planContract = planContract;
            this._windowManager = windowManager;
        }

        #endregion

        #region # 属性

        #region 作业计划编号 —— string PlanNo
        /// <summary>
        /// 作业计划编号
        /// </summary>
        [DependencyProperty]
        public string PlanNo { get; set; }
        #endregion

        #region 作业计划名称 —— string PlanName
        /// <summary>
        /// 作业计划名称
        /// </summary>
        [DependencyProperty]
        public string PlanName { get; set; }
        #endregion

        #region 生产批号 —— string ProductionBatchNo
        /// <summary>
        /// 生产批号
        /// </summary>
        [DependencyProperty]
        public string ProductionBatchNo { get; set; }
        #endregion

        #region 预期开始时间 —— DateTime? ExpStartTime
        /// <summary>
        /// 预期开始时间
        /// </summary>
        [DependencyProperty]
        public DateTime? ExpStartTime { get; set; }
        #endregion

        #region 预期结束时间 —— DateTime? ExpEndTime
        /// <summary>
        /// 预期结束时间
        /// </summary>
        [DependencyProperty]
        public DateTime? ExpEndTime { get; set; }
        #endregion

        #region 最早开始时间 —— DateTime? EarliestStartTime
        /// <summary>
        /// 最早开始时间
        /// </summary>
        [DependencyProperty]
        public DateTime? EarliestStartTime { get; set; }
        #endregion

        #region 最晚结束时间 —— DateTime? LatestEndTime
        /// <summary>
        /// 最晚结束时间
        /// </summary>
        [DependencyProperty]
        public DateTime? LatestEndTime { get; set; }
        #endregion

        #region 已选产品 —— MaterialInfo SelectedProduct
        /// <summary>
        /// 已选产品
        /// </summary>
        [DependencyProperty]
        public MaterialInfo SelectedProduct { get; set; }
        #endregion

        #region 已选工艺 —— ProcessInfo SelectedProcess
        /// <summary>
        /// 已选工艺
        /// </summary>
        [DependencyProperty]
        public ProcessInfo SelectedProcess { get; set; }
        #endregion

        #region 已选物料清单 —— BomInfo SelectedBom
        /// <summary>
        /// 已选物料清单
        /// </summary>
        [DependencyProperty]
        public BomInfo SelectedBom { get; set; }
        #endregion

        #region 预期毛产量 —— decimal? ExpGrossQuantity
        /// <summary>
        /// 预期毛产量
        /// </summary>
        [DependencyProperty]
        public decimal? ExpGrossQuantity { get; set; }
        #endregion

        #region 预期净产量 —— decimal? ExpNetQuantity
        /// <summary>
        /// 预期净产量
        /// </summary>
        [DependencyProperty]
        public decimal? ExpNetQuantity { get; set; }
        #endregion

        #region 单位 —— string Unit
        /// <summary>
        /// 单位
        /// </summary>
        [DependencyProperty]
        public string Unit { get; set; }
        #endregion

        #region 已选生产计划 —— ProductionPlanInfo SelectedProductionPlan
        /// <summary>
        /// 已选生产计划
        /// </summary>
        [DependencyProperty]
        public ProductionPlanInfo SelectedProductionPlan { get; set; }
        #endregion

        #region 已选工厂模型 —— Node SelectedFacility 
        /// <summary>
        /// 已选工厂模型
        /// </summary>
        [DependencyProperty]
        public Node SelectedFacility { get; set; }
        #endregion

        #region 优先级 —— int? Priority
        /// <summary>
        /// 优先级
        /// </summary>
        /// <remarks>数值越大，优先级越高</remarks>
        [DependencyProperty]
        public int? Priority { get; set; }
        #endregion

        #region 描述 —— string Description
        /// <summary>
        /// 描述
        /// </summary>
        [DependencyProperty]
        public string Description { get; set; }
        #endregion

        #region 产品列表 —— ObservableCollection<MaterialInfo> Products
        /// <summary>
        /// 产品列表
        /// </summary>
        [DependencyProperty]
        public ObservableCollection<MaterialInfo> Products { get; set; }
        #endregion

        #region 工艺列表 —— ObservableCollection<ProcessInfo> Processes
        /// <summary>
        /// 工艺列表
        /// </summary>
        [DependencyProperty]
        public ObservableCollection<ProcessInfo> Processes { get; set; }
        #endregion

        #region 物料清单列表 —— ObservableCollection<BomInfo> Boms
        /// <summary>
        /// 物料清单列表
        /// </summary>
        [DependencyProperty]
        public ObservableCollection<BomInfo> Boms { get; set; }
        #endregion

        #endregion

        #region # 方法

        //Initializations

        #region 加载 —— async Task Load(IEnumerable<MaterialInfo> products)
        /// <summary>
        /// 加载
        /// </summary>
        /// <param name="products">产品列表</param>
        public async Task Load(IEnumerable<MaterialInfo> products)
        {
            this.Products = new ObservableCollection<MaterialInfo>(products);
            this.PlanNo = await Task.Run(() => this._numberContract.Channel.GenerateExecutionPlanNo());
        }
        #endregion


        //Actions

        #region 选择生产计划 —— async void SelectProductionPlan()
        /// <summary>
        /// 选择生产计划
        /// </summary>
        public async void SelectProductionPlan()
        {
            this.Busy();

            SelectProductionPlanViewModel viewModel = ResolveMediator.Resolve<SelectProductionPlanViewModel>();
            viewModel.Load(false, null, null);
            bool? result = await this._windowManager.ShowDialogAsync(viewModel);
            if (result == true)
            {
                Wrap<ProductionPlanInfo> wrap = viewModel.ProductionPlans.Single(x => x.IsChecked == true);
                this.SelectedProductionPlan = wrap.Model;
            }

            this.Idle();
        }
        #endregion

        #region 清空生产计划 —— void ClearProductionPlan()
        /// <summary>
        /// 清空生产计划
        /// </summary>
        public void ClearProductionPlan()
        {
            this.SelectedProductionPlan = null;
        }
        #endregion

        #region 选择工厂模型 —— async void SelectFacility()
        /// <summary>
        /// 选择工厂模型
        /// </summary>
        public async void SelectFacility()
        {
            this.Busy();

            SelectFacilityViewModel viewModel = ResolveMediator.Resolve<SelectFacilityViewModel>();
            bool? result = await this._windowManager.ShowDialogAsync(viewModel);
            if (result == true)
            {
                this.SelectedFacility = viewModel.SelectedFacility;
            }

            this.Idle();
        }
        #endregion

        #region 清空工厂模型 —— void ClearFacility()
        /// <summary>
        /// 清空工厂模型
        /// </summary>
        public void ClearFacility()
        {
            this.SelectedFacility = null;
        }
        #endregion

        #region 加载单位、工艺列表与物料清单列表 —— async void LoadUnitProcessesAndBoms()
        /// <summary>
        /// 加载单位、工艺列表与物料清单列表
        /// </summary>
        public async void LoadUnitProcessesAndBoms()
        {
            #region # 验证

            if (this.SelectedProduct == null)
            {
                this.Unit = null;
                this.Boms = new ObservableCollection<BomInfo>();
                this.Processes = new ObservableCollection<ProcessInfo>();
                return;
            }

            #endregion

            this.Unit = this.SelectedProduct.StandardUnitNo;

            IDefinitionContract definitionContract = this._definitionContract.Channel;
            IEnumerable<BomInfo> boms = await Task.Run(() => definitionContract.GetBomsByPage(null, this.SelectedProduct.Id, null, true, CheckStatus.Passed, 1, int.MaxValue).Datas);
            IEnumerable<ProcessInfo> processes = await Task.Run(() => definitionContract.GetProcessesByPage(null, null, this.SelectedProduct.Id, null, true, CheckStatus.Passed, 1, int.MaxValue).Datas);
            this.Boms = new ObservableCollection<BomInfo>(boms);
            this.Processes = new ObservableCollection<ProcessInfo>(processes);
        }
        #endregion

        #region 提交 —— async void Submit()
        /// <summary>
        /// 提交
        /// </summary>
        public async void Submit()
        {
            #region # 验证

            if (string.IsNullOrWhiteSpace(this.PlanNo))
            {
                MessageBox.Show("计划编号不可为空！", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
                return;
            }
            if (string.IsNullOrWhiteSpace(this.PlanName))
            {
                MessageBox.Show("计划名称不可为空！", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
                return;
            }
            if (this.SelectedProduct == null)
            {
                MessageBox.Show("产品不可为空！", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
                return;
            }
            if (this.SelectedProcess == null)
            {
                MessageBox.Show("工艺不可为空！", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
                return;
            }
            if (this.SelectedBom == null)
            {
                MessageBox.Show("物料清单不可为空！", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
                return;
            }
            if (this.ExpStartTime == null)
            {
                MessageBox.Show("预期开始时间不可为空！", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
                return;
            }
            if (this.ExpEndTime == null)
            {
                MessageBox.Show("预期结束时间不可为空！", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
                return;
            }
            if (this.EarliestStartTime == null)
            {
                MessageBox.Show("最早开始时间不可为空！", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
                return;
            }
            if (this.LatestEndTime == null)
            {
                MessageBox.Show("最晚结束时间不可为空！", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
                return;
            }
            if (this.ExpGrossQuantity == null)
            {
                MessageBox.Show("预期毛产量不可为空！", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
                return;
            }
            if (this.ExpNetQuantity == null)
            {
                MessageBox.Show("预期净产量不可为空！", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
                return;
            }
            if (this.Priority == null)
            {
                MessageBox.Show("优先级不可为空！", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
                return;
            }

            #endregion

            this.Busy();

            string planNo = this.PlanNo;
            string planName = this.PlanName;
            string productionBatchNo = this.ProductionBatchNo;
            DateTime expStartTime = this.ExpStartTime.Value;
            DateTime expEndTime = this.ExpEndTime.Value;
            DateTime earliestStartTime = this.EarliestStartTime.Value;
            DateTime latestEndTime = this.LatestEndTime.Value;
            Guid productId = this.SelectedProduct.Id;
            Guid processId = this.SelectedProcess.Id;
            Guid bomId = this.SelectedBom.Id;
            decimal expGrossQuantity = this.ExpGrossQuantity.Value;
            decimal expNetQuantity = this.ExpNetQuantity.Value;
            Guid? productionPlanId = this.SelectedProductionPlan?.Id;
            Guid? facilityId = this.SelectedFacility?.Id;
            int priority = this.Priority.Value;
            string description = this.Description;

            await Task.Run(() => this._planContract.Channel.CreateExecutionPlan(planNo, planName, productionBatchNo, expStartTime, expEndTime, earliestStartTime, latestEndTime, productId, processId, bomId, expGrossQuantity, expNetQuantity, productionPlanId, facilityId, priority, description));

            await base.TryCloseAsync(true);
            this.Idle();
        }
        #endregion

        #endregion
    }
}
